package com.strato.transaction.v1_0_0.api.jdbc;

import com.strato.transaction.v1_0_0.api.TransactionManager;
import com.strato.transaction.v1_0_0.api.TransactionStatus;
import com.strato.transaction.v1_0_0.api.TransactionStatusHolder;

public class DataSourceTransactionManager implements TransactionManager {

	@Override
	public TransactionStatus beginTransaction() {
		DataSourceTransactionStatus status=new DataSourceTransactionStatus();
		return status;
	}

	@Override
	public void rollback(TransactionStatus status) {
		if(status==null){
			return;
		}
		status.rollback();
	}

	@Override
	public void commit(TransactionStatus status) {
		if(status==null){
			return;
		}
		status.commit();
	}

	@Override
	public void endTransaction(TransactionStatus status) {
		if(status!=null){
			status.close();
		}
	}

	public static <T> T requiresNew(Execution<T> execution){
		TransactionStatus backupStatus = TransactionStatusHolder.get();
		TransactionStatus newTx=new DataSourceTransactionStatus();
		try{
			TransactionStatusHolder.hold(newTx);
			T result=execution.execute();
			newTx.commit();
			return result;
		}catch(Throwable e){
			newTx.rollback();
			throw e;
		}finally{
			TransactionStatusHolder.unhold();
			newTx.close();
			TransactionStatusHolder.hold(backupStatus);
		}
	}
	public static <T> T required(Execution<T> execution){
		TransactionStatus currentStatus = TransactionStatusHolder.get();
		boolean createNew=false;
		if(currentStatus==null){
			createNew=true;
			currentStatus=new DataSourceTransactionStatus();
			TransactionStatusHolder.hold(currentStatus);
		}
		try{
			T result=execution.execute();
			if(createNew){
				currentStatus.commit();
			}
			return result;
		}catch(Throwable e){
			if(createNew){
				currentStatus.rollback();
			}
			throw e;
		}finally{
			if(createNew){
				TransactionStatusHolder.unhold();
				currentStatus.close();
			}
		}
	}
	
	@Deprecated
	public static void requiresNew(Runnable execution){
		TransactionStatus backupStatus = TransactionStatusHolder.get();
		TransactionStatus newTx=new DataSourceTransactionStatus();
		try{
			TransactionStatusHolder.hold(newTx);
			execution.run();
			newTx.commit();
		}catch(Throwable e){
			newTx.rollback();
			throw e;
		}finally{
			TransactionStatusHolder.unhold();
			newTx.close();
			TransactionStatusHolder.hold(backupStatus);
		}
	}

	@Deprecated
	public static void required(Runnable execution){
		TransactionStatus currentStatus = TransactionStatusHolder.get();
		boolean createNew=false;
		if(currentStatus==null){
			createNew=true;
			currentStatus=new DataSourceTransactionStatus();
			TransactionStatusHolder.hold(currentStatus);
		}
		try{
			execution.run();
			if(createNew){
				currentStatus.commit();
			}
		}catch(Throwable e){
			if(createNew){
				currentStatus.rollback();
			}
			throw e;
		}finally{
			if(createNew){
				TransactionStatusHolder.unhold();
				currentStatus.close();
			}
		}
	}
}
